using System;
using System.Text;

namespace IQIGame.Onigao.Framework
{
    class SiByteBuffer : IDisposable
    {
        public const int STR_OR_BYTES_MAX_LENGTH = 10 * 1000 * 1024;

        //字节缓存区，需保证数组中都是小端模式数据，否则容易出错
        private byte[] _buf;
        //读取索引
        private int _readIndex = 0;
        //写入索引
        private int _writeIndex = 0;
        //缓存区字节数组的长度
        private int _capacity;

        /// <summary>
        /// 构造方法
        /// </summary>
        /// <param name="capacity">初始容量</param>
        private SiByteBuffer(int capacity)
        {
            _buf = new byte[capacity];
            _capacity = capacity;
            _readIndex = 0;
            _writeIndex = 0;
        }

        /// <summary>
        /// 构造方法
        /// </summary>
        private SiByteBuffer(byte[] bytes)
        {
            Init(bytes, 0, bytes.Length);
        }

        private SiByteBuffer(byte[] bytes, int offset, int length)
        {
            Init(bytes, offset, length);
        }

        public void Init(byte[] bytes, int offset, int length)
        {
            _buf = bytes;
            _capacity = bytes.Length;
            _readIndex = offset;
            _writeIndex = length + offset;
        }

        /// <summary>
        /// 构建一个capacity长度的字节缓存区ByteBuffer对象
        /// </summary>
        /// <param name="capacity">初始容量</param>
        /// </param>
        /// <returns>ByteBuffer对象</returns>
        public static SiByteBuffer Allocate(int capacity)
        {
            return new SiByteBuffer(capacity);
        }

        /// <summary>
        /// 构建缓冲区
        /// </summary>
        /// <param name="bytes">源数据</param>
        /// <returns></returns>
        public static SiByteBuffer Wrap(byte[] bytes)
        {
            return new SiByteBuffer(bytes);
        }

        /// <summary>
        /// 构建缓冲区
        /// </summary>
        /// <param name="bytes">源数据</param>
        /// <param name="offset">offset</param>
        /// <param name="length">length</param>
        /// <returns></returns>
        public static SiByteBuffer Wrap(byte[] bytes, int offset, int length)
        {
            return new SiByteBuffer(bytes, offset, length);
        }

        public bool HasRemaining()
        {
            return _readIndex < _writeIndex;
        }

        /// <summary>
        /// 根据value，确定大于此length的最近的2次方数，如length=7，则返回值为8；length=12，则返回16
        /// </summary>
        /// <param name="value">参考容量</param>
        /// <returns>比参考容量大的最接近的2次方数</returns>
        private int FixLength(int value)
        {
            if (value == 0)
            {
                return 1;
            }
            value--;
            value |= value >> 1;
            value |= value >> 2;
            value |= value >> 4;
            value |= value >> 8;
            value |= value >> 16;
            return value + 1;
        }

        public void EnsureWrite(int size)
        {
            FixSizeAndExpand(_writeIndex + size);
        }

        /// <summary>
        /// 确定内部字节缓存数组的大小
        /// </summary>
        /// <param name="futureLen">将来的容量</param>
        private void FixSizeAndExpand(int futureLen)
        {
            if (futureLen > _capacity)
            {
                //以原大小的2次方数的两倍确定内部字节缓存区大小
                int size = FixLength(_capacity) * 2;
                if (futureLen > size)
                {
                    //以将来的大小的2次方的两倍确定内部字节缓存区大小
                    size = FixLength(futureLen) * 2;
                }
                byte[] newbuf = new byte[size];
                Buffer.BlockCopy(_buf, 0, newbuf, 0, _capacity);
                _buf = newbuf;
                _capacity = size;
            }
        }

        /// <summary>
        /// 将bytes字节数组从startIndex开始的length字节写入到此缓存区
        /// </summary>
        /// <param name="bytes">源数据</param>
        /// <param name="offset">源数据开始的位置</param>
        /// <param name="len">写入的长度</param>
        private void WriteBytes(byte[] bytes, int offset, int len)
        {
            if (len < 0) return;
            int total = _writeIndex + len;
            FixSizeAndExpand(total);
            Buffer.BlockCopy(bytes, offset, _buf, _writeIndex, len);
            _writeIndex = total;
        }

        private void WriteBytes(Span<byte> bytes)
        {
            int len = bytes.Length;
            int total = _writeIndex + len;
            FixSizeAndExpand(total);
            bytes.CopyTo(_buf.AsSpan(_writeIndex, len));
            _writeIndex = total;
        }

        /// <summary>
        /// 写入一个byte数据
        /// </summary>
        /// <param name="value">byte数据</param>
        public void WriteByte(byte value)
        {
            int afterLen = _writeIndex + 1;
            FixSizeAndExpand(afterLen);
            _buf[_writeIndex] = value;
            _writeIndex = afterLen;
        }

        private void SetByte(int index, byte value)
        {
            _buf[index] = value;
        }

        /// <summary>
        /// 从读取索引位置开始读取len长度的字节数组
        /// </summary>
        /// <param name="len">待读取的字节长度</param>
        /// <returns>字节数组</returns>
        private byte[] Read(int len)
        {
            byte[] bytes = new byte[len];
            Buffer.BlockCopy(_buf, _readIndex, bytes, 0, len);
            _readIndex += len;
            return bytes;
        }

        /// <summary>
        /// 读取一个字节
        /// </summary>
        /// <returns>字节数据</returns>
        public byte Read()
        {
            return _buf[_readIndex++];
        }

        /// <summary>
        /// 设置/获取读指针位置
        /// </summary>
        public int ReaderIndex
        {
            get
            {
                return _readIndex;
            }
            set
            {
                if (value < 0) return;
                _readIndex = value;
            }
        }

        /// <summary>
        /// 设置/获取写指针位置
        /// </summary>
        public int WriterIndex
        {
            get
            {
                return _writeIndex;
            }
            set
            {
                if (value < 0) return;
                _writeIndex = value;
            }
        }

        /// <summary>
        /// 可读的有效字节数
        /// </summary>
        /// <returns>可读的字节数</returns>
        public int ReadableBytes
        {
            get
            {
                return _writeIndex - _readIndex;
            }
        }

        /// <summary>
        /// 获取缓存区容量大小
        /// </summary>
        /// <returns>缓存区容量</returns>
        public int Capacity
        {
            get
            {
                return _capacity;
            }
        }

        /// <summary>
        /// 当前写入大小
        /// </summary>
        public int Size
        {
            get
            {
                return _writeIndex;
            }
        }

        /// <summary>
        /// 获取可读的字节数组
        /// </summary>
        /// <returns>字节数据</returns>
        public byte[] ToByteArray()
        {
            byte[] bytes = new byte[_writeIndex];
            Buffer.BlockCopy(_buf, 0, bytes, 0, bytes.Length);
            return bytes;
        }

        public byte[] Buf
        {
            get
            {
                return _buf;
            }
        }

        /// <summary>
        /// 清空此对象，但保留字节缓存数组（空数组）
        /// </summary>
        public void Clear()
        {
            //Array.Clear(_buf);
            _readIndex = 0;
            _writeIndex = 0;
        }

        /// <summary>
        /// 释放对象，清除字节缓存数组。如果此对象可池化，则推入到对象池
        /// </summary>
        public void Dispose()
        {
            _buf = null;
            _readIndex = 0;
            _writeIndex = 0;
            _capacity = 0;
        }

        public int ReadInt()
        {
            int value = _buf[_readIndex++];
            value |= _buf[_readIndex++] << 8;
            value |= _buf[_readIndex++] << 16;
            value |= _buf[_readIndex++] << 24;
            return value;
        }

        public void WriteInt(int value)
        {
            EnsureWrite(4);
            _buf[_writeIndex++] = (byte)value;
            _buf[_writeIndex++] = (byte)(value >> 8);
            _buf[_writeIndex++] = (byte)(value >> 16);
            _buf[_writeIndex++] = (byte)(value >> 24);
        }

        public void SetInt(int index, int value)
        {
            int oldIndex = _writeIndex;
            _writeIndex = index;
            WriteInt(value);
            _writeIndex = oldIndex;
        }

        public uint ReadSize(byte identity)
        {
            int flag = identity & 0x0f;
            if (flag == 0)
            {
                return 0U;
            }
            if (flag == 0x01)
            {
                return _buf[_readIndex++];
            }

            uint value = 0U;
            if ((identity & 0x01) != 0)
            {
                value |= _buf[_readIndex++];
            }
            if ((identity & 0x01 << 1) != 0)
            {
                value |= (uint)_buf[_readIndex++] << 8;
            }
            if ((identity & 0x01 << 2) != 0)
            {
                value |= (uint)_buf[_readIndex++] << 16;
            }
            if ((identity & 0x01 << 3) != 0)
            {
                value |= (uint)_buf[_readIndex++] << 24;
            }
            return value;
        }

        public void WriteSize(uint value, byte sign)
        {
            if (value == 0U)
            {
                WriteByte(sign);
                return;
            }
            if (value < 0xffU)
            {
                EnsureWrite(2);
                _buf[_writeIndex++] = (byte)(sign | 0x01);
                _buf[_writeIndex++] = (byte)value;
                return;
            }

            int flag = _writeIndex;
            EnsureWrite(5);
            _writeIndex++;

            byte tmp = (byte)value;
            if (tmp != 0)
            {
                sign |= 0x01;
                _buf[_writeIndex++] = tmp;
            }

            tmp = (byte)(value >> 8);
            if (tmp != 0)
            {
                sign |= 0x01 << 1;
                _buf[_writeIndex++] = tmp;
            }

            tmp = (byte)(value >> 16);
            if (tmp != 0)
            {
                sign |= 0x01 << 2;
                _buf[_writeIndex++] = tmp;
            }

            tmp = (byte)(value >> 24);
            if (tmp != 0)
            {
                sign |= 0x01 << 3;
                _buf[_writeIndex++] = tmp;
            }
            _buf[flag] = sign;
        }


        #region read and wirte stype

        public sbyte Read_byte()
        {
            byte identity = _buf[_readIndex++];
            if (identity == SType.BYTE)
            {
                return 0;
            }
            if ((byte)(identity & 0xf0) != SType.BYTE)
            {
                throw new Exception("cann't convert to byte");
            }
            return (sbyte)_buf[_readIndex++];
        }

        public byte Read_ubyte()
        {
            byte identity = _buf[_readIndex++];
            if (identity == SType.UBYTE)
            {
                return 0;
            }
            if ((byte)(identity & 0xf0) != SType.UBYTE)
            {
                throw new Exception("cann't convert to ubyte");
            }
            return _buf[_readIndex++];
        }

        public bool Read_boolean()
        {
            byte identity = _buf[_readIndex++];
            if ((byte)(identity & 0xf0) != SType.BOOLEAN)
            {
                throw new Exception("cann't convert to boolean");
            }
            return (identity & 0x01) != 0;
        }

        public short Read_short()
        {
            byte identity = _buf[_readIndex++];
            if (identity == SType.SHORT)
            {
                return 0;
            }
            if ((byte)(identity & 0xf0) != SType.SHORT)
            {
                throw new Exception("cann't convert to short");
            }
            if ((identity & 0x0f) == 0x01)
            {
                return _buf[_readIndex++];
            }

            int value = 0;
            if ((identity & 0x01) != 0)
            {
                value |= _buf[_readIndex++];
            }
            if ((identity & 0x01 << 1) != 0)
            {
                value |= _buf[_readIndex++] << 8;
            }
            return (short)value;
        }

        public ushort Read_ushort()
        {
            byte identity = _buf[_readIndex++];
            if (identity == SType.USHORT)
            {
                return 0;
            }
            if ((byte)(identity & 0xf0) != SType.USHORT)
            {
                throw new Exception("cann't convert to ushort");
            }
            if ((identity & 0x0f) == 0x01)
            {
                return _buf[_readIndex++];
            }
            int value = 0;
            if ((identity & 0x01) != 0)
            {
                value |= _buf[_readIndex++];
            }
            if ((identity & 0x01 << 1) != 0)
            {
                value |= _buf[_readIndex++] << 8;
            }
            return (ushort)value;
        }

        public int Read_int()
        {
            byte identity = _buf[_readIndex++];
            if (identity == SType.INT)
            {
                return 0;
            }
            if ((byte)(identity & 0xf0) != SType.INT)
            {
                throw new Exception("cann't convert to int");
            }
            int tag = identity & 0x0f;
            if (tag == 0x01)
            {
                return _buf[_readIndex++];
            }
            if (tag == 0x03)
            {
                return _buf[_readIndex++] | _buf[_readIndex++] << 8;
            }
            if (tag == 0x07)
            {
                return _buf[_readIndex++] | _buf[_readIndex++] << 8 | _buf[_readIndex++] << 16;
            }
            int value = 0;
            if ((identity & 0x01) != 0)
            {
                value |= _buf[_readIndex++];
            }
            if ((identity & 0x01 << 1) != 0)
            {
                value |= _buf[_readIndex++] << 8;
            }
            if ((identity & 0x01 << 2) != 0)
            {
                value |= _buf[_readIndex++] << 16;
            }
            if ((identity & 0x01 << 3) != 0)
            {
                value |= _buf[_readIndex++] << 24;
            }
            return value;
        }

        public uint Read_uint()
        {
            byte identity = _buf[_readIndex++];
            if (identity == SType.UINT)
            {
                return 0U;
            }
            if ((byte)(identity & 0xf0) != SType.UINT)
            {
                throw new Exception("cann't convert to uint");
            }
            int tag = identity & 0x0f;
            if (tag == 0x01)
            {
                return _buf[_readIndex++];
            }
            if (tag == 0x03)
            {
                return (uint)(_buf[_readIndex++] | _buf[_readIndex++] << 8);
            }
            if (tag == 0x07)
            {
                return (uint)(_buf[_readIndex++] | _buf[_readIndex++] << 8 | _buf[_readIndex++] << 16);
            }

            uint value = 0U;
            if ((identity & 0x01) != 0)
            {
                value |= _buf[_readIndex++];
            }
            if ((identity & 0x01 << 1) != 0)
            {
                value |= (uint)_buf[_readIndex++] << 8;
            }
            if ((identity & 0x01 << 2) != 0)
            {
                value |= (uint)_buf[_readIndex++] << 16;
            }
            if ((identity & 0x01 << 3) != 0)
            {
                value |= (uint)_buf[_readIndex++] << 24;
            }
            return value;
        }

        public long Read_long()
        {
            byte identity = _buf[_readIndex++];
            if (identity == SType.LONG)
            {
                return 0L;
            }
            if ((byte)(identity & 0xf0) != SType.LONG)
            {
                throw new Exception("cann't convert to long");
            }
            int valueCount = identity & 0x0f;
            long value = 0L;
            for (int i = 0; i < valueCount; i++)
            {
                value |= (long)_buf[_readIndex++] << i * 8;
            }
            return value;
        }

        public unsafe float Read_float()
        {
            byte identity = _buf[_readIndex++];
            if (identity == SType.FLOAT)
            {
                return 0f;
            }
            if ((byte)(identity & 0xf0) != SType.FLOAT)
            {
                throw new Exception("cann't convert to float");
            }
            int value = 0;
            if ((identity & 0x01) != 0)
            {
                value |= _buf[_readIndex++];
            }
            if ((identity & 0x01 << 1) != 0)
            {
                value |= _buf[_readIndex++] << 8;
            }
            if ((identity & 0x01 << 2) != 0)
            {
                value |= _buf[_readIndex++] << 16;
            }
            if ((identity & 0x01 << 3) != 0)
            {
                value |= _buf[_readIndex++] << 24;
            }
            return *(float*)&value;
        }

        public unsafe double Read_double()
        {
            byte identity = _buf[_readIndex++];
            if (identity == SType.DOUBLE)
            {
                return 0D;
            }
            if ((byte)(identity & 0xf0) != SType.DOUBLE)
            {
                throw new Exception("cann't convert to double");
            }
            long value = 0L;
            int valueCount = identity & 0x0f;
            for (int i = 0; i < valueCount; i++)
            {
                value |= (long)_buf[_readIndex++] << (7 - i) * 8;
            }
            return *(double*)&value;
        }

        public string Read_string()
        {
            byte identity = _buf[_readIndex++];
            if (identity == SType.NULL)
            {
                return null;
            }
            if ((byte)(identity & 0xf0) != SType.STRING)
            {
                throw new Exception("cann't convert to string");
            }
            int length = (int)ReadSize(identity);
            if (length > 0)
            {
                if (length > STR_OR_BYTES_MAX_LENGTH)
                {
                    throw new Exception("length to big");
                }
                string s = Encoding.UTF8.GetString(_buf, _readIndex, length);
                _readIndex += length;
                return s;
            }
            else if (length == 0)
            {
                return "";
            }
            else
            {
                throw new Exception("string length less than 0");
            }
        }

        public byte[] Read_bytes()
        {
            byte identity = _buf[_readIndex++];
            if (identity == SType.NULL)
            {
                return null;
            }
            if ((byte)(identity & 0xf0) != SType.BYTES)
            {
                throw new Exception("cann't convert to bytes");
            }
            int length = (int)ReadSize(identity);
            if (length > 0)
            {
                if (length > STR_OR_BYTES_MAX_LENGTH)
                {
                    throw new Exception("length to big");
                }
                return Read(length);
            }
            else if (length == 0)
            {
                return Array.Empty<byte>();
            }
            else
            {
                throw new Exception("string length less than 0");
            }
        }

        public Span<byte> Read_bytes_span()
        {
            byte identity = _buf[_readIndex++];
            if (identity == SType.NULL)
            {
                return null;
            }
            if ((byte)(identity & 0xf0) != SType.BYTES)
            {
                throw new Exception("cann't convert to bytes");
            }
            int length = (int)ReadSize(identity);
            if (length > 0)
            {
                if (length > STR_OR_BYTES_MAX_LENGTH)
                {
                    throw new Exception("length to big");
                }
                Span<byte> span = new Span<byte>(_buf, _readIndex, length);
                _readIndex += length;
                return span;
            }
            else if (length == 0)
            {
                return Array.Empty<byte>();
            }
            else
            {
                throw new Exception("string length less than 0");
            }
        }

        public void Write_ubyte(byte value)
        {
            if (value == 0)
            {
                WriteByte(SType.UBYTE);
                return;
            }
            EnsureWrite(2);
            _buf[_writeIndex++] = SType.UBYTE | 0x01;
            _buf[_writeIndex++] = value;
        }

        public void Write_short(short value)
        {
            if (value == 0)
            {
                WriteByte(SType.SHORT);
                return;
            }
            if (value < 0xff && value > 0)
            {
                EnsureWrite(2);
                _buf[_writeIndex++] = SType.SHORT | 0x01;
                _buf[_writeIndex++] = (byte)value;
                return;
            }

            byte sign = SType.SHORT;
            int flag = _writeIndex;
            EnsureWrite(3);
            _writeIndex++;

            byte tmp = (byte)value;
            if (tmp != 0)
            {
                sign |= 0x01;
                _buf[_writeIndex++] = tmp;
            }

            tmp = (byte)(value >> 8);
            if (tmp != 0)
            {
                sign |= 0x01 << 1;
                _buf[_writeIndex++] = tmp;
            }
            _buf[flag] = sign;
        }

        public void Write_int(int value)
        {
            if (value == 0)
            {
                WriteByte(SType.INT);
                return;
            }
            if (value < 0xff && value > 0)
            {
                EnsureWrite(2);
                _buf[_writeIndex++] = SType.INT | 0x01;
                _buf[_writeIndex++] = (byte)value;
                return;
            }

            byte sign = SType.INT;
            int flag = _writeIndex;
            EnsureWrite(5);
            _writeIndex++;

            byte tmp = (byte)value;
            if (tmp != 0)
            {
                sign |= 0x01;
                _buf[_writeIndex++] = tmp;
            }

            tmp = (byte)(value >> 8);
            if (tmp != 0)
            {
                sign |= 0x01 << 1;
                _buf[_writeIndex++] = tmp;
            }

            tmp = (byte)(value >> 16);
            if (tmp != 0)
            {
                sign |= 0x01 << 2;
                _buf[_writeIndex++] = tmp;
            }

            tmp = (byte)(value >> 24);
            if (tmp != 0)
            {
                sign |= 0x01 << 3;
                _buf[_writeIndex++] = tmp;
            }
            _buf[flag] = sign;
        }

        public void Write_long(long value)
        {
            if (value == 0L)
            {
                WriteByte(SType.LONG);
                return;
            }
            if (value < 0xffL && value > 0L)
            {
                EnsureWrite(2);
                _buf[_writeIndex++] = SType.LONG | 0x01;
                _buf[_writeIndex++] = (byte)value;
                return;
            }
            int flag = _writeIndex;
            EnsureWrite(9);
            _writeIndex++;
            int valueCount = 0;//从低位往高位算一共多少个字节有值
            byte tmp;
            for (int i = 0; i < 8; i++)
            {
                tmp = (byte)(value >> i * 8);
                if (tmp != 0)
                {
                    valueCount = i + 1;
                    _buf[_writeIndex + i] = tmp;
                }
                else
                {
                    _buf[_writeIndex + i] = 0;
                }
            }
            _writeIndex += valueCount;
            _buf[flag] = (byte)(SType.LONG | valueCount);
        }

        public void Write_byte(sbyte value)
        {
            if (value == 0)
            {
                WriteByte(SType.BYTE);
                return;
            }
            EnsureWrite(2);
            _buf[_writeIndex++] = SType.BYTE | 0x01;
            _buf[_writeIndex++] = (byte)value;
        }

        public void Write_boolean(bool value)
        {
            if (value)
            {
                WriteByte(SType.BOOLEAN | 0x01);
            }
            else
            {
                WriteByte(SType.BOOLEAN);
            }
        }

        public unsafe void Write_float(float d)
        {
            if (d == 0f)
            {
                WriteByte(SType.FLOAT);
                return;
            }
            int value = *(int*)&d;
            byte sign = SType.FLOAT;
            int flag = _writeIndex;
            EnsureWrite(5);
            _writeIndex++;

            byte tmp = (byte)value;
            if (tmp != 0)
            {
                sign |= 0x01;
                _buf[_writeIndex++] = tmp;
            }

            tmp = (byte)(value >> 8);
            if (tmp != 0)
            {
                sign |= 0x01 << 1;
                _buf[_writeIndex++] = tmp;
            }

            tmp = (byte)(value >> 16);
            if (tmp != 0)
            {
                sign |= 0x01 << 2;
                _buf[_writeIndex++] = tmp;
            }

            tmp = (byte)(value >> 24);
            if (tmp != 0)
            {
                sign |= 0x01 << 3;
                _buf[_writeIndex++] = tmp;
            }
            _buf[flag] = sign;
        }

        public unsafe void Write_double(double value)
        {
            if (value == 0d)
            {
                WriteByte(SType.DOUBLE);
                return;
            }

            long d = *(long*)&value;
            int flag = _writeIndex;
            EnsureWrite(9);
            _writeIndex++;
            byte tmp;
            int valueCount = 0;//double是从高位到低位的字节数量
            for (int i = 0; i < 8; i++)
            {
                tmp = (byte)(d >> (7 - i) * 8);
                if (tmp != 0)
                {
                    valueCount = i + 1;
                    _buf[_writeIndex + i] = tmp;
                }
                else
                {
                    _buf[_writeIndex + i] = 0;
                }
            }
            _writeIndex += valueCount;
            _buf[flag] = (byte)(SType.DOUBLE | valueCount);
        }

        public void Write_ushort(ushort value)
        {
            if (value == 0)
            {
                WriteByte(SType.USHORT);
                return;
            }
            if (value < 0xff)
            {
                EnsureWrite(2);
                _buf[_writeIndex++] = SType.USHORT | 0x01;
                _buf[_writeIndex++] = (byte)value;
                return;
            }

            byte sign = SType.USHORT;
            int flag = _writeIndex;
            EnsureWrite(3);
            _writeIndex++;

            byte tmp = (byte)value;
            if (tmp != 0)
            {
                sign |= 0x01;
                _buf[_writeIndex++] = tmp;
            }

            tmp = (byte)(value >> 8);
            if (tmp != 0)
            {
                sign |= 0x01 << 1;
                _buf[_writeIndex++] = tmp;
            }
            _buf[flag] = sign;
        }

        public void Write_uint(uint value)
        {
            if (value == 0U)
            {
                WriteByte(SType.UINT);
                return;
            }
            if (value < 0xffU)
            {
                EnsureWrite(2);
                _buf[_writeIndex++] = SType.UINT | 0x01;
                _buf[_writeIndex++] = (byte)value;
                return;
            }

            byte sign = SType.UINT;
            int flag = _writeIndex;
            EnsureWrite(5);
            _writeIndex++;

            byte tmp = (byte)value;
            if (tmp != 0)
            {
                sign |= 0x01;
                _buf[_writeIndex++] = tmp;
            }

            tmp = (byte)(value >> 8);
            if (tmp != 0)
            {
                sign |= 0x01 << 1;
                _buf[_writeIndex++] = tmp;
            }

            tmp = (byte)(value >> 16);
            if (tmp != 0)
            {
                sign |= 0x01 << 2;
                _buf[_writeIndex++] = tmp;
            }

            tmp = (byte)(value >> 24);
            if (tmp != 0)
            {
                sign |= 0x01 << 3;
                _buf[_writeIndex++] = tmp;
            }
            _buf[flag] = sign;
        }

        public void Write_bytes(byte[] value)
        {
            if (value == null)
            {
                WriteByte(SType.NULL);
                return;
            }
            int length = value.Length;
            if (length > STR_OR_BYTES_MAX_LENGTH)
            {
                throw new Exception("length to big");
            }
            WriteSize((uint)length, SType.BYTES);
            WriteBytes(value, 0, length);
        }

        public void Write_bytes_span(Span<byte> value)
        {
            if (value == null)
            {
                WriteByte(SType.NULL);
                return;
            }
            int length = value.Length;
            if (length > STR_OR_BYTES_MAX_LENGTH)
            {
                throw new Exception("length to big");
            }
            WriteSize((uint)length, SType.BYTES);
            WriteBytes(value);
        }

        public void Write_string(string value)
        {
            if (value == null)
            {
                WriteByte(SType.NULL);
                return;
            }
            int strLength = value.Length;
            if (strLength == 0)
            {
                WriteSize(0, SType.STRING);
            }
            else
            {
                int length = Encoding.UTF8.GetByteCount(value);
                if (length > STR_OR_BYTES_MAX_LENGTH)
                {
                    throw new Exception("length to big");
                }
                WriteSize((uint)length, SType.STRING);
                EnsureWrite(length);
                Encoding.UTF8.GetBytes(value, 0, value.Length, Buf, WriterIndex);
                _writeIndex += length;
            }
        }

        public void WriteNull()
        {
            WriteByte(SType.NULL);
        }
        #endregion

    }

}
